package net.sourceforge.peers.gui;

import zdh.avatar.softphone.Register;
import zdh.avatar.softphone.Softphone;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import net.sourceforge.peers.Config;
import net.sourceforge.peers.Logger;
import net.sourceforge.peers.media.MediaManager;
import net.sourceforge.peers.sip.RFC3261;
import net.sourceforge.peers.sip.Utils;
import net.sourceforge.peers.sip.core.useragent.SipListener;
import net.sourceforge.peers.sip.core.useragent.UserAgent;
import net.sourceforge.peers.sip.syntaxencoding.SipUriSyntaxException;
import net.sourceforge.peers.sip.transactionuser.Dialog;
import net.sourceforge.peers.sip.transactionuser.DialogManager;
import net.sourceforge.peers.sip.transport.SipRequest;
import net.sourceforge.peers.sip.transport.SipResponse;

public class EventManager implements SipListener, MainFrameListener,
        CallFrameListener, ActionListener {

    public static final String PEERS_URL = "http://peers.sourceforge.net/";
    public static final String PEERS_USER_MANUAL = PEERS_URL + "user_manual";
    public static final String ACTION_EXIT = "Exit";
    public static final String ACTION_ACCOUNT = "Account";
    public static final String ACTION_PREFERENCES = "Preferences";
    public static final String ACTION_ABOUT = "About";
    public static final String ACTION_DOCUMENTATION = "Documentation";

    public UserAgent userAgent;
    private AccountFrame accountFrame;
    private Softphone softphone;
    private Register register;
    private boolean closed;
    private Logger logger;

    public EventManager(Softphone softphone, String peersHome, Logger logger) {
        this.softphone = softphone;
        this.logger = logger;
        closed = false;
        
	// create sip stack

        try {
            userAgent = new UserAgent(this, peersHome, logger);
        } catch (SocketException e) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null, "Peers sip port "
                            + "unavailable, about to leave", "Error",
                            JOptionPane.ERROR_MESSAGE);
                    System.exit(1);
                }
            });
        }
    }

    // SIP EVENTS
    @Override
    public void registering(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (register != null) {
                    register.registering(sipRequest);
                }
                softphone.registering(sipRequest);
            }
        });
    }

    @Override
    public synchronized void registerFailed(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (register != null) {
                    register.registerFailed(sipResponse);
                }
                softphone.registerFailed(sipResponse);
            }
        });

    }

    @Override
    public synchronized void registerSuccessful(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (closed) {
                    userAgent.close();
                    System.exit(0);
                    return;
                }
                if (register != null) {
                    register.registerSuccess(sipResponse);
                }
                softphone.registerSuccessful(sipResponse);
            }
        });

    }

    @Override
    public synchronized void calleePickup(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (softphone != null) {
                    softphone.calleePickup();
                }
            }

        });

    }

    @Override
    public synchronized void error(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (softphone != null) {
                    softphone.error(sipResponse);
                }
            }
        });

    }

    @Override
    public synchronized void incomingCall(final SipRequest sipRequest,
            SipResponse provResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
	   //	SipHeaders sipHeaders = sipRequest.getSipHeaders();
//	SipHeaderFieldName sipHeaderFieldName =
//			   new SipHeaderFieldName(RFC3261.HDR_FROM);
//	SipHeaderFieldValue from = sipHeaders.get(sipHeaderFieldName);
//	final String fromValue = from.getValue();
//	String callId = Utils.getMessageCallId(sipRequest);
//        CallFrame softphone = new CallFrame(fromValue, callId, this, logger);
//	Softphone softphone = new Softphone(fromValue, callId, this, logger);
//	softphones.put(callId, softphone);

	// TODO: set fromValue, callId for incoming call
                softphone.setSipRequest(sipRequest);
                softphone.incomingCall();
            }
        });

    }

    @Override
    public synchronized void remoteHangup(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (softphone != null) {
                    softphone.remoteHangup();
                }
            }
        });
    }

    @Override
    public synchronized void ringing(SipResponse sipResponse) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (softphone != null) {
                    softphone.ringing();
                }
            }
        });

    }

    // main frame events
    @Override
    public void register() throws SipUriSyntaxException {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (userAgent == null) {
	    // if several peers instances are launched concurrently,
                    // display error message and exit
                    return;
                }

                Config config = userAgent.getConfig();
                if (config.getPassword() != null) {
                    try {
                        userAgent.getUac().register();
                    } catch (SipUriSyntaxException ex) {

                    }
                }
            }
        });

    }

    @Override
    public synchronized void callClicked(final String uri) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                String callId = Utils.generateCallID(
                        userAgent.getConfig().getLocalInetAddress());
//        CallFrame softphone = new CallFrame(uri, callId, this, logger);
//	Softphone softphone = new Softphone(uri, callId, this, logger);
//	softphone.put(callId, softphone);

                SipRequest sipRequest;
                try {
                    sipRequest = userAgent.getUac().invite(uri, callId);
                } catch (SipUriSyntaxException e) {
                    logger.error(e.getMessage(), e);
                    softphone.setLabelText(e.getMessage());
                    return;
                }

                softphone.setSipRequest(sipRequest);
                softphone.callClicked();
            }
        });

    }

    @Override
    public synchronized void windowClosed() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    userAgent.getUac().unregister();
                } catch (Exception e) {
                    logger.error("error while unregistering", e);
                }
                closed = true;
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3 * RFC3261.TIMER_T1);
                        } catch (InterruptedException e) {
                        }
                        System.exit(0);
                    }
                });
                thread.start();
            }
        });

    }

    // call frame events
    @Override
    public synchronized void hangupClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                userAgent.getUac().terminate(sipRequest);
            }
        });

    }

    @Override
    public synchronized void pickupClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                String callId = Utils.getMessageCallId(sipRequest);
                DialogManager dialogManager = userAgent.getDialogManager();
                Dialog dialog = dialogManager.getDialog(callId);
                userAgent.getUas().acceptCall(sipRequest, dialog);
            }
        });

    }

    @Override
    public synchronized void busyHereClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                userAgent.getUas().rejectCall(sipRequest);
            }
        });
    }

    @Override
    public void dtmf(final char digit) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MediaManager mediaManager = userAgent.getMediaManager();
                mediaManager.sendDtmf(digit);
            }
        });

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String action = e.getActionCommand();
        logger.debug("gui actionPerformed() " + action);
        Runnable runnable = null;
        switch (action) {
            case ACTION_EXIT:
                runnable = new Runnable() {
                    @Override
                    public void run() {
                        windowClosed();
                    }
                };
                break;
            case ACTION_ACCOUNT:
                runnable = new Runnable() {
                    @Override
                    public void run() {
                        if (register == null || !register.isDisplayable()) {
                            register = new Register(softphone, logger);
                            register.showWindow();
                        } else {
                            register.requestFocus();
                        }
                    }
                };
                break;
            case ACTION_PREFERENCES:
                runnable = new Runnable() {
                    @Override
                    public void run() {
                        JOptionPane.showMessageDialog(null, "Not implemented yet");
                    }
                };
                break;
            case ACTION_ABOUT:
//                runnable = new Runnable() {
//                    @Override
//                    public void run() {
//                        AboutFrame aboutFrame = new AboutFrame(
//                                userAgent.getPeersHome(), logger);
//                        aboutFrame.setVisible(true);
//                    }
//                };
                break;
            case ACTION_DOCUMENTATION:
                runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            URI uri = new URI(PEERS_USER_MANUAL);
                            java.awt.Desktop.getDesktop().browse(uri);
                        } catch (URISyntaxException e) {
                            logger.error(e.getMessage(), e);
                        } catch (IOException e) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                };
                break;
        }
        if (runnable != null) {
            SwingUtilities.invokeLater(runnable);
        }
    }
}
